<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:xs="http://www.w3.org/2001/XMLSchema"
                xmlns:pkg="http://expath.org/ns/pkg"
                xmlns:web="http://expath.org/ns/webapp"
                xmlns:app="http://fgeorges.org/ns/xqts/browser"
                xmlns:suite="http://fgeorges.org/ns/xqts/suite"
                xmlns:xqts="http://www.w3.org/2005/02/query-test-XQTSCatalog"
                xmlns:xf="http://www.w3.org/2002/xforms"
                xmlns:html="http://www.w3.org/1999/xhtml"
                xmlns="http://www.w3.org/1999/xhtml"
                exclude-result-prefixes="#all"
                version="2.0">

   <xsl:import href="http://fgeorges.org/ns/xqts/suite.xsl"/>

   <pkg:import-uri>http://fgeorges.org/ns/xqts/browser/servlets.xsl</pkg:import-uri>

   <!--
       FIXME: TODO: See the comment in expath-web.xml...
   -->
   <xsl:function name="app:redirect" as="element(web:response)">
      <xsl:param name="request" as="element(web:request)"/>
      <xsl:variable name="what" as="element(web:param)" select="
          $request/web:param[@name = ('case', 'group', 'browse')]"/>
      <web:response status="302" message="Redirect">
         <web:header name="Location" value="{ $what/@name }/{ $what/@value }"/>
         <web:body content-type="text/plain">
            <xsl:text>You should be rediected to the requested page...</xsl:text>
         </web:body>
      </web:response>
   </xsl:function>

   <xsl:function name="app:table-line" as="element(html:tr)*">
      <xsl:param name="name"  as="xs:string"/>
      <xsl:param name="infos" as="item()*"/>
      <tr>
         <th>
            <xsl:value-of select="$name"/>
         </th>
         <td>
            <span>
               <xsl:for-each select="$infos">
                  <xsl:if test="position() gt 1">
                     <br/>
                  </xsl:if>
                  <xsl:sequence select="."/>
               </xsl:for-each>
            </span>
         </td>
      </tr>
   </xsl:function>

   <!--
       Redirect a suite resource to the deployed xqts-suite library.
   -->
   <xsl:function name="app:suite-file" as="element(web:response)">
      <xsl:param name="request" as="element(web:request)"/>
      <xsl:variable name="name" as="xs:string" select="
          $request/web:path/web:match[@name eq 'file']"/>
      <xsl:variable name="res" as="xs:string+" select="app:do-suite-file($name)"/>
      <web:response status="200" message="OK">
         <web:body content-type="{ $res[2] }" src="{ $res[1] }"/>
      </web:response>
   </xsl:function>

   <xsl:function name="app:do-suite-file" as="xs:string+">
      <xsl:param name="name" as="xs:string"/>
      <xsl:variable name="uri"  as="xs:anyURI" select="suite:resolve-file($name)"/>
      <xsl:variable name="mime" as="xs:string" select="
          doc('mimetypes.xml')/*/type[ends-with($name, @extension)]/@mime"/>
      <xsl:sequence select="$uri, $mime"/>
   </xsl:function>

   <xsl:function name="app:resource" as="element(web:response)">
      <xsl:param name="request" as="element(web:request)"/>
      <xsl:variable name="name" as="xs:string" select="
          $request/web:path/web:match[@name eq 'rsrc']"/>
      <xsl:variable name="res" as="xs:string+" select="app:do-resource($name)"/>
      <web:response status="200" message="OK">
         <web:body content-type="{ $res[2] }" src="{ $res[1] }"/>
      </web:response>
   </xsl:function>

   <xsl:function name="app:do-resource" as="xs:string+">
      <xsl:param name="name" as="xs:string"/>
      <xsl:variable name="uri"  as="xs:anyURI" select="resolve-uri($name)"/>
      <xsl:variable name="mime" as="xs:string" select="
          doc('mimetypes.xml')/*/type[ends-with($name, @extension)]/@mime"/>
      <xsl:sequence select="$uri, $mime"/>
   </xsl:function>

   <xsl:function name="app:home">
      <xsl:param name="request" as="element(web:request)"/>
      <web:response status="200" message="Ok">
         <web:body content-type="application/xml" method="xhtml">
            <!-- TODO: ... -->
            <!--xsl:processing-instruction name="xml-stylesheet">
               <xsl:text>href="xsltforms/xsltforms.xsl" type="text/xsl"</xsl:text>
            </xsl:processing-instruction>
            <xsl:processing-instruction name="xsltforms-options">
               <xsl:text>debug="yes"</xsl:text>
            </xsl:processing-instruction-->
            <html>
               <head>
                  <title>XQTS browser</title>
                  <xf:model>
                     <xf:instance>
                        <data xmlns="">
                           <group/>
                        </data>
                     </xf:instance>
                     <xf:submission id="redirect-1" method="post" ref="group">
                        <xf:resource value="'../webapp-tools/dump'"/>
                     </xf:submission>
                     <xf:submission id="redirect-2" method="post" ref="group"
                                    resource="../webapp-tools/dump"/>
                     <xf:submission id="redirect-3" method="post" ref="group"
                                    resource="http://h2oconsulting.be/tools/dump"/>
                  </xf:model>
               </head>
               <body>
                  <xsl:sequence select="app:do-home()"/>
               </body>
            </html>
         </web:body>
      </web:response>
   </xsl:function>

   <!--
       TODO: I'm trying to add XForms support through XSLTForms.  That
       means the caller needs to setup XSLTForms by creating the PI
       <?xml-stylesheet href="xsltforms/xsltforms.xsl" type="text/xsl"?>
       at the top of the returned document, and put the model in the
       HTML head...
   -->
   <xsl:function name="app:do-home">
      <h2><span>XQTS browser</span></h2>
      <p>
         Welcome to the XQTS browser.  This application provides
         support to navigate within the XQTS test suite, the test
         suite for the XQuery spec, developed by the W3C and available
         at <a
         href="http://w3.org/XML/Query/test-suite/">http://w3.org/XML/Query/test-suite/</a>.
      </p>
      <p>
         It provides a hierarchical browser through the test groups
         and cases.  When browsing from top-level, only groups are
         dispayed; when you click on a paticular group, it restricts
         the browsing to that sub-tree, including the test cases.  It
         also provides a detail page for each group and each case.  To
         acces directly a case or group page, type in its id below and
         press <em>enter</em>:
      </p>
      <table border="1" width="100%" cellpadding="3" cellspacing="0">
         <tr>
            <th>top-level browsing</th>
            <td>
               <a href="browse/">browse/</a>
            </td>
         </tr>
         <tr>
            <th>browsing a particular group</th>
            <td>
               <form action="redirect" method="get">
                  <xsl:text>browse/</xsl:text>
                  <input type="text" name="browse"/>
                  <input type="submit" value="Submit" style="visibility: hidden; width: 0"/>
               </form>
            </td>
         </tr>
         <tr>
            <th>test group details</th>
            <td>
               <form action="redirect" method="get">
                  <xsl:text>group/</xsl:text>
                  <input type="text" name="group"/>
                  <input type="submit" value="Submit" style="visibility: hidden; width: 0"/>
               </form>
            </td>
         </tr>
         <tr>
            <th>test case details</th>
            <td>
               <form action="redirect" method="get">
                  <xsl:text>case/</xsl:text>
                  <input type="text" name="case"/>
                  <input type="submit" value="Submit" style="visibility: hidden; width: 0"/>
               </form>
            </td>
         </tr>
         <!-- TODO: ... -->
         <!--tr>
            <th>test group details (XForms...)</th>
            <td>
               <xf:input ref="group">
                  <xf:label>group/</xf:label>
               </xf:input>
               <xf:submit submission="redirect-1">
                  <xf:label>Elem</xf:label>
               </xf:submit>
               <xf:submit submission="redirect-2">
                  <xf:label>Attr</xf:label>
               </xf:submit>
               <xf:submit submission="redirect-3">
                  <xf:label>Ext</xf:label>
               </xf:submit>
            </td>
         </tr-->
      </table>
      <p>
         If you want to upload an XQTS result document to have direct
         links to the test case detail page for corresponding failing
         tests, please use the form below.  The document must be valid
         against the schema <a
         href="suite/ReportingResults/XQTSResult.xsd">XQTSResult.xsd</a>
         (in the XQTS distribution), like the following <a
         href="suite/ReportingResults/XQTSSampleResult.xml">example
         file</a>.  Please select your file:
         <form action="results" method="post" enctype="multipart/form-data">
            <input type="file" name="results" size="50"/>
            <input type="submit" value="Send"/>
         </form>
      </p>
   </xsl:function>

   <xsl:function name="app:results">
      <xsl:param name="input" as="node()+"/>
      <xsl:variable name="body" select="remove($input, 1)" as="document-node()"/>
      <web:response status="200" message="Ok">
         <web:body content-type="text/html" method="xhtml"/>
      </web:response>
      <html>
         <head>
            <title>XQTS browser</title>
         </head>
         <body>
            <xsl:sequence select="app:do-results($body/*)"/>
         </body>
      </html>
   </xsl:function>

   <xsl:function name="app:do-results" xmlns:res="http://www.w3.org/2005/02/query-test-XQTSResult">
      <xsl:param name="results" as="element(res:test-suite-result)"/>
      <h2><span>XQTS browser</span></h2>
      <p>(back to <a href="./">browser home</a>)</p>
      <h3>Implementation</h3>
      <p>
         <xsl:value-of select="$results/res:implementation/@name"/>
         <xsl:text>, </xsl:text>
         <xsl:value-of select="$results/res:implementation/@version"/>
      </p>
      <xsl:variable name="failed"     select="$results/res:test-case[@result eq 'fail']"/>
      <xsl:variable name="not-appl"   select="$results/res:test-case[@result eq 'not applicable']"/>
      <xsl:variable name="not-tested" select="$results/res:test-case[@result eq 'not tested']"/>
      <xsl:variable name="undefined"  select="$results/res:test-case[@result eq 'cannot tell']"/>
      <xsl:choose>
         <xsl:when test="exists($failed | $not-appl | $not-tested | $undefined)">
            <xsl:sequence select="
                app:format-result-group($failed,     'Failing tests'),
                app:format-result-group($not-appl,   'Not applicable tests'),
                app:format-result-group($not-tested, 'Not tested tests'),
                app:format-result-group($undefined,  'Undefined state')"/>
         </xsl:when>
         <xsl:otherwise>
            <p>All tests passed, congratulations!</p>
         </xsl:otherwise>
      </xsl:choose>
   </xsl:function>

   <xsl:function name="app:format-result-group"
                 xmlns:res="http://www.w3.org/2005/02/query-test-XQTSResult">
      <xsl:param name="tests" as="element(res:test-case)*"/>
      <xsl:param name="title" as="xs:string"/>
      <xsl:if test="exists($tests)">
         <h3>
            <xsl:value-of select="$title"/>
            <xsl:text>: #</xsl:text>
            <xsl:value-of select="count($tests)"/>
         </h3>
         <ul>
            <xsl:for-each select="$tests">
               <li>
                  <a href="case/{ @name }">
                     <xsl:value-of select="@name"/>
                  </a>
               </li>
            </xsl:for-each>
         </ul>
      </xsl:if>
   </xsl:function>

   <xsl:function name="app:browse">
      <xsl:param name="request" as="element(web:request)"/>
      <xsl:variable name="name" as="xs:string?" select="
          $request/web:path/web:match[@name eq 'name']"/>
      <web:response status="200" message="Ok">
         <web:body content-type="text/html" method="xhtml"/>
      </web:response>
      <html>
         <head>
            <title>XQTS browser</title>
            <script type="text/javascript" src="../mktree/mktree.js"/>
            <link rel="stylesheet" href="../mktree/mktree.css" type="text/css"/>
         </head>
         <body>
            <xsl:sequence select="app:do-browse($name)"/>
         </body>
      </html>
   </xsl:function>

   <xsl:function name="app:do-browse">
      <xsl:param name="name" as="xs:string?"/>
      <h2><span>XQTS browser</span></h2>
      <p>(back to <a href="../">browser home</a>)</p>
      <xsl:variable name="suite" as="element(xqts:test-suite)" select="
          document(suite:resolve-file('XQTSCatalog.xml'))/*"/>
      <xsl:variable name="group" as="element(xqts:test-group)+" select="
          if ( $name ) then
            $suite//xqts:test-group[@name eq $name]
          else
            $suite/xqts:test-group"/>
      <xsl:apply-templates select="$suite/xqts:test-suite-info" mode="browse"/>
      <!-- TODO: Add a link to the level above... (the parent group) -->
      <ul class="mktree">
         <xsl:apply-templates select="$group" mode="browse">
            <xsl:with-param
                name="include-cases"
                select="exists($name) and $name ne ''"
                tunnel="yes"/>
         </xsl:apply-templates>
      </ul>
   </xsl:function>

   <xsl:template match="xqts:test-suite-info" mode="browse">
      <p>
         <xsl:value-of select="xqts:title"/>
      </p>
      <p>
         <xsl:value-of select="xqts:description"/>
      </p>
   </xsl:template>

   <xsl:template match="xqts:test-group" mode="browse">
      <xsl:param name="include-cases" tunnel="yes" as="xs:boolean"/>
      <li>
         <a href="{ @name }">
            <xsl:value-of select="xqts:GroupInfo/xqts:title"/>
         </a>
         <xsl:text> (</xsl:text>
         <a href="../group/{ @name }">details</a>
         <xsl:text>)</xsl:text>
         <xsl:variable name="elems" select="xqts:test-case[$include-cases]|xqts:test-group"/>
         <xsl:if test="exists($elems)">
            <ul>
               <xsl:apply-templates select="$elems" mode="browse"/>
            </ul>
         </xsl:if>
      </li>
   </xsl:template>

   <xsl:template match="xqts:test-case" mode="browse">
      <li>
         <a href="../case/{ @name }">
            <xsl:value-of select="@name"/>
         </a>
         <xsl:text>: </xsl:text>
         <xsl:value-of select="xqts:description"/>
      </li>
   </xsl:template>

   <xsl:function name="app:case">
      <xsl:param name="request" as="element(web:request)"/>
      <xsl:variable name="name" as="xs:string" select="
          $request/web:path/web:match[@name eq 'name']"/>
      <web:response status="200" message="Ok">
         <web:body content-type="text/html" method="xhtml"/>
      </web:response>
      <html>
         <head>
            <title>XQTS browser</title>
            <script type="text/javascript" src="../sh/shCore.js"/>
            <script type="text/javascript" src="../sh/shBrushXml.js"/>
            <script type="text/javascript" src="../sh/shBrushXQuery.js"/>
            <link rel="stylesheet" type="text/css" href="../sh/shCore.css"/>
            <link rel="stylesheet" type="text/css" href="../sh/shThemeDefault.css"/>
         </head>
         <body>
            <xsl:sequence select="app:do-case($name)"/>
            <script type="text/javascript">
               SyntaxHighlighter.all()
            </script>
         </body>
      </html>
   </xsl:function>

   <xsl:function name="app:do-case">
      <xsl:param name="name" as="xs:string"/>
      <h2><span>XQTS browser</span></h2>
      <p>(back to <a href="../">browser home</a>)</p>
      <xsl:variable name="suite" as="element(xqts:test-suite)" select="
          document(suite:resolve-file('XQTSCatalog.xml'))/*"/>
      <xsl:variable name="case" as="element(xqts:test-case)" select="
          $suite//xqts:test-case[@name eq $name]"/>
      <xsl:apply-templates select="$case" mode="case"/>
   </xsl:function>

   <xsl:template match="xqts:test-case" mode="case">
      <!-- TODO: Work on what info are displayed, and how! -->
      <xsl:variable name="this" select="."/>
      <h3>Synopsys</h3>
      <table border="1" width="100%" cellpadding="3" cellspacing="0">
         <xsl:sequence select="app:table-line('Name', @name/string(.))"/>
         <xsl:sequence select="app:table-line('Description', xqts:description/string(.))"/>
         <xsl:sequence select="app:table-line('Note', xqts:note/string(.))"/>
         <xsl:variable name="cit" as="element(html:span)*">
            <!-- TODO: Damn, use template rules! -->
            <xsl:for-each select="xqts:spec-citation">
               <xsl:variable name="spec" as="element(xqts:spec-citation)" select="."/>
               <!-- TODO: Use a key? (No, because we don't need to
                    build an index each time; but factorize that out
                    with app:error-line()...) -->
               <xsl:variable name="spec-uri" as="xs:string" select="
                   /*/xqts:citations/xqts:citation-spec[@name eq $spec/@spec]/xqts:spec-URI"/>
               <span>
                  <xsl:text>[</xsl:text>
                  <xsl:value-of select="$spec/@spec"/>
                  <xsl:text>] </xsl:text>
                  <xsl:value-of select="$spec/@section-number"/>
                  <xsl:text> </xsl:text>
                  <a href="{ $spec-uri }#{ $spec/@section-pointer }">
                     <xsl:value-of select="$spec/@section-title"/>
                  </a>
               </span>
            </xsl:for-each>
         </xsl:variable>
         <xsl:sequence select="app:table-line('Spec ref.', $cit)"/>
         <xsl:variable name="query" as="element(html:span)+">
            <xsl:variable name="path" select="concat(@FilePath, xqts:query/@name, '.xq')"/>
            <xsl:variable name="xq" select="
                concat('Queries/XQuery/', @FilePath, xqts:query/@name, '.xq')"/>
            <xsl:variable name="xqx" select="
                concat('Queries/XQueryX/', @FilePath, xqts:query/@name, '.xqx')"/>
            <span>
               <xsl:text>Queries/XQuery/</xsl:text>
               <xsl:value-of select="@FilePath"/>
               <a href="../suite/Queries/XQuery/{ @FilePath }{ xqts:query/@name }.xq">
                  <xsl:value-of select="xqts:query/@name"/>
                  <xsl:text>.xq</xsl:text>
               </a>
            </span>
            <span>
               <xsl:text>Queries/XQueryX/</xsl:text>
               <xsl:value-of select="@FilePath"/>
               <a href="../suite/Queries/XQueryX/{ @FilePath }{ xqts:query/@name }.xqx">
                  <xsl:value-of select="xqts:query/@name"/>
                  <xsl:text>.xqx</xsl:text>
               </a>
            </span>
         </xsl:variable>
         <xsl:sequence select="app:table-line('Query', $query)"/>
         <xsl:sequence select="app:input-output-line('Input', xqts:input-file)"/>
         <xsl:sequence select="app:input-output-line('Output', xqts:output-file)"/>
         <!-- TODO: Make the errors a link to their definition in the specs. -->
         <!-- How?  Is there a function that can give a URI from an error code? -->
         <xsl:sequence select="app:error-line(.)"/>
         <xsl:sequence select="
             app:table-line(
               'Groups',
               app:make-group-path(ancestor::xqts:test-group))"/>
         <xsl:variable name="resos" as="element(html:a)*">
            <!-- TODO: Damn, use template rules! -->
            <xsl:for-each select="xqts:reflects-resolution">
               <a href="{ . }">
                  <xsl:value-of select="
                      if ( matches(., '\?id=[0-9]+$') ) then
                        replace(., '.+\?id=([0-9]+)$', 'Bug $1')
                      else
                        string(.)"/>
               </a>
            </xsl:for-each>
         </xsl:variable>
         <xsl:sequence select="app:table-line('Reflects', $resos)"/>
      </table>
      <h3>Query</h3>
      <!-- TODO: Damn, use template rules! -->
      <pre class="brush: xquery" style="border-style: dotted; border-width: 1px; padding: 10px">
         <xsl:variable name="uri" select="
             suite:resolve-file(concat('Queries/XQuery/', @FilePath, xqts:query/@name, '.xq'))"/>
         <xsl:value-of select="replace(unparsed-text($uri), '&#13;&#10;', '&#10;')"/>
      </pre>
      <h3>XQueryX</h3>
      <!-- TODO: Damn, use template rules! -->
      <pre class="brush: xml" style="border-style: dotted; border-width: 1px; padding: 10px">
         <xsl:variable name="uri" select="
             suite:resolve-file(concat('Queries/XQueryX/', @FilePath, xqts:query/@name, '.xqx'))"/>
         <xsl:value-of select="replace(unparsed-text($uri), '&#13;&#10;', '&#10;')"/>
      </pre>
      <h3>Input</h3>
      <xsl:apply-templates select="xqts:input-file" mode="show"/>
      <h3>Output</h3>
      <xsl:apply-templates select="xqts:output-file" mode="show"/>
   </xsl:template>

   <!--
       TODO: Doc...
       
       FIXME: All input-file and output-file do NOT refer to files...!
       Some refer to variable names...
   -->
   <xsl:function name="app:input-output-line">
      <xsl:param name="label" as="xs:string"/>
      <xsl:param name="files" as="element()*"/>
      <xsl:variable name="files" as="element(html:span)*">
         <xsl:apply-templates select="$files" mode="case"/>
      </xsl:variable>
      <xsl:sequence select="app:table-line($label, $files)"/>
   </xsl:function>

   <xsl:template match="xqts:input-file" mode="case">
      <xsl:variable name="source" as="element(xqts:source)" select="
          root()/*/xqts:sources/xqts:source[@ID eq current()]"/>
      <xsl:variable name="file" as="xs:string" select="$source/@FileName"/>
      <span>
         <xsl:choose>
            <xsl:when test="contains($file, '/')">
               <xsl:value-of select="substring-before($file, '/')"/>
               <xsl:text>/</xsl:text>
               <a href="../suite/{ $file }">
                  <xsl:value-of select="substring-after($file, '/')"/>
               </a>
            </xsl:when>
            <xsl:otherwise>
                <a href="../suite/{ $file }">
                   <xsl:value-of select="$file"/>
                </a>
            </xsl:otherwise>
         </xsl:choose>
      </span>
      <span style="color: #666">
         <xsl:text> &#xA0;&#xA0;&#xA0;&#xA0;&#xA0; (</xsl:text>
         <xsl:value-of select="$source/xqts:description"/>
         <xsl:text>)</xsl:text>
      </span>
   </xsl:template>

   <!-- TODO: Factorize with rule for xqts:input-file in mode case. -->
   <xsl:template match="xqts:input-file" mode="show">
      <xsl:variable name="source" as="element(xqts:source)" select="
          root()/*/xqts:sources/xqts:source[@ID eq current()]"/>
      <p>
         <b>
            <xsl:value-of select="$source/@ID"/>
         </b>
         <xsl:text>: </xsl:text>
         <xsl:value-of select="$source/xqts:description"/>
      </p>
      <xsl:variable name="uri" select="suite:resolve-file($source/@FileName)"/>
      <pre style="border-style: dotted; border-width: 1px; padding: 10px">
         <xsl:value-of select="replace(unparsed-text($uri), '&#13;&#10;', '&#10;')"/>
      </pre>
   </xsl:template>

   <xsl:template match="xqts:output-file[empty(node())]" mode="case" priority="10"/>

   <xsl:template match="xqts:output-file" mode="case">
      <span>
         <xsl:text>ExpectedTestResults/</xsl:text>
         <xsl:value-of select="../@FilePath"/>
         <a href="../suite/ExpectedTestResults/{ ../@FilePath }{ . }">
            <xsl:value-of select="."/>
         </a>
      </span>
   </xsl:template>

   <xsl:template match="xqts:output-file[empty(node())]" mode="show" priority="10"/>

   <xsl:template match="xqts:output-file" mode="show">
      <xsl:variable name="uri" select="
          suite:resolve-file(concat('ExpectedTestResults/', ../@FilePath, .))"/>
      <pre style="border-style: dotted; border-width: 1px; padding: 10px">
         <xsl:value-of select="replace(unparsed-text($uri), '&#13;&#10;', '&#10;')"/>
      </pre>
   </xsl:template>

   <!--
       TODO: Doc...
   -->
   <xsl:function name="app:error-line">
      <xsl:param name="case" as="element(xqts:test-case)"/>
      <xsl:variable name="errors" as="element(html:span)*">
         <xsl:apply-templates select="$case/xqts:expected-error" mode="case"/>
      </xsl:variable>
      <xsl:sequence select="app:table-line('Expected error', $errors)"/>
   </xsl:function>

   <xsl:template match="xqts:expected-error[. eq '*']" mode="case">
      <span>* [any error]</span>
   </xsl:template>

   <xsl:template match="xqts:expected-error[. ne '*']" mode="case">
      <span>
         <a href="{ app:get-error-citation(., root()/*) }">
            <xsl:value-of select="."/>
         </a>
         <!-- the next node if it is a comment, maybe with a blank
              text node in between (TODO: should probably be
              removed..., see Mike's email from 2010-08-17) -->
         <xsl:variable name="comment" select="
             following-sibling::node()[1][self::comment()]
             | following-sibling::node()[1][self::text()][normalize-space(.) eq '']
               / following-sibling::node()[1][self::comment()]"/>
         <xsl:if test="exists($comment)">
            <xsl:text> (</xsl:text>
            <xsl:value-of select="normalize-space($comment)"/>
            <xsl:text>)</xsl:text>
         </xsl:if>
      </span>
   </xsl:template>

   <xsl:function name="app:get-error-citation">
      <xsl:param name="error" as="xs:string"/>
      <xsl:param name="suite" as="element(xqts:test-suite)"/>
      <xsl:variable name="mapping">
         <err prefix="FO" spec="FuncOps"/>
         <err prefix="SE" spec="Serialization"/>
         <err prefix="XP" spec="XPath"/>
         <err prefix="XQ" spec="XQuery"/>
      </xsl:variable>
      <xsl:variable name="spec" as="xs:string" select="
          $mapping/*[@prefix eq substring($error, 1, 2)]/@spec"/>
      <!-- TODO: XP* error codes are present in the suite catalog, but
           there is no citation for the XPath spec -->
      <xsl:variable name="uri" as="xs:string" select="
          if ( $spec eq 'XPath' ) then
            'http://www.w3.org/TR/xpath20/' (: hord-coded for now... :)
          else
            $suite/xqts:citations/xqts:citation-spec[@name eq $spec]/xqts:spec-URI"/>
      <xsl:sequence select="concat($uri, '#ERR', $error)"/>
   </xsl:function>

   <xsl:function name="app:group">
      <xsl:param name="request" as="element(web:request)"/>
      <xsl:variable name="name" as="xs:string" select="
          $request/web:path/web:match[@name eq 'name']"/>
      <web:response status="200" message="Ok">
         <web:body content-type="text/html" method="xhtml"/>
      </web:response>
      <html>
         <head>
            <title>XQTS browser</title>
         </head>
         <body>
            <xsl:sequence select="app:do-group($name)"/>
         </body>
      </html>
   </xsl:function>

   <xsl:function name="app:do-group">
      <xsl:param name="name" as="xs:string"/>
      <h2><span>XQTS browser</span></h2>
      <xsl:variable name="suite" as="element(xqts:test-suite)" select="
          document(suite:resolve-file('XQTSCatalog.xml'))/*"/>
      <xsl:variable name="group" as="element(xqts:test-group)" select="
          $suite//xqts:test-group[@name eq $name]"/>
      <xsl:apply-templates select="$group" mode="group"/>
      <p>(back to <a href="../">browser home</a>)</p>
   </xsl:function>

   <xsl:template match="xqts:test-group" mode="group">
      <!-- TODO: Work on what info are displayed, and how! -->
      <p>
         <xsl:text>(</xsl:text>
         <a href="../browse/{ @name }">browse</a>
         <xsl:text>)</xsl:text>
      </p>
      <table border="1" width="100%" cellpadding="3" cellspacing="0">
         <xsl:sequence select="app:table-line('Name', @name/string(.))"/>
         <xsl:sequence select="app:table-line('Title', xqts:GroupInfo/xqts:title/string(.))"/>
         <xsl:sequence select="app:table-line('Description',
                                              xqts:GroupInfo/xqts:description/string(.))"/>
         <xsl:sequence select="app:table-line('Note', xqts:GroupInfo/xqts:note/string(.))"/>
         <xsl:sequence select="
             app:table-line(
               'Parents',
               app:make-group-path(ancestor::xqts:test-group))"/>
      </table>
   </xsl:template>

   <xsl:function name="app:make-group-path">
      <xsl:param name="groups" as="element(xqts:test-group)*"/>
      <xsl:if test="exists($groups)">
         <a href="../group/{ $groups[1]/@name }">
            <xsl:value-of select="$groups[1]/xqts:GroupInfo/xqts:title"/>
         </a>
         <xsl:sequence select="app:make-group-path(remove($groups, 1))"/>
      </xsl:if>
   </xsl:function>

</xsl:stylesheet>
